import wx
import math
import random
import os
import pickle
import wx.lib.sized_controls as sc
import sys
sys.path.append('./svbnodes')
from baseNode import baseNode

DEFINEDNODES = ["None","Move","Keyboard","Rotate", "Action", "If", "Set Property", "Add Object", "Delay", "Portal", "Portal In", "Set Velocity", "Collides"]


def is_int(s):
    try: 
        int(s)
        return True
    except ValueError:
        return False

def NodeToCode(node, nodeGuiData):
    returnVal = ""
    returnVal += "class " + node.name + "(object):\n"
    returnVal += "    def __init__(self, gameObject):\n"
    returnVal += "        self.gameObject=gameObject\n"



    if(nodeGuiData.guidata['title'] == "Move"):
        if(nodeGuiData.getParam('String','Object') != "gameObject"):
            returnVal += "        " + "scene = bge.logic.getCurrentScene()\n"
            returnVal += "        " + "self.gameObject = scene.objects[gameObject[\"" +nodeGuiData.getParam('String','Object') +"\"]]\n"
        returnVal += "        " + "self.x = " + str(nodeGuiData.getParam('float','x')) + "/10\n"
        returnVal += "        " + "self.y = " + str(nodeGuiData.getParam('float','y')) + "/10\n"
        returnVal += "        " + "self.z = " + str(nodeGuiData.getParam('float','z')) + "/10\n"
        returnVal += "    def next(self):\n"
        returnVal += "        self.gameObject.applyMovement((self.x,self.y,self.z),True)\n"
        returnVal += "        return self.p0()\n"
        returnVal += "    def nextDelayed(self):\n"
        returnVal += "            return []\n"
        returnVal += "    def nextPortal(self):\n"
        returnVal += "        return []\n"


    elif(nodeGuiData.guidata['title'] == "Keyboard"):
        returnVal += "        self.keyboard = bge.logic.keyboard\n"
        playOption = nodeGuiData.getParam('combo','Type')[1][nodeGuiData.getParam('combo','Type')[0]]
        if(playOption == "Just Activated"):
            playMode = "bge.logic.KX_INPUT_JUST_ACTIVATED"
        elif(playOption == "Active"):
            playMode = "bge.logic.KX_INPUT_ACTIVE"
        elif(playOption == "Just Released"):
            playMode = "bge.logic.KX_INPUT_JUST_RELEASED"
        returnVal += "        " + "self.playMode = " + playMode + "\n"

        returnVal += "    def next(self):\n"
        returnVal += "        if(self.keyboard.events[bge.events." + str(nodeGuiData.getParam('char','key')).upper() +"KEY]) == self.playMode:\n"
        returnVal += "            return self.p0()\n"
        returnVal += "    def nextDelayed(self):\n"
        returnVal += "            return []\n"
        returnVal += "    def nextPortal(self):\n"
        returnVal += "        return []\n"


    elif(nodeGuiData.guidata['title'] == "Rotate"):
        if(nodeGuiData.getParam('String','Object') != "gameObject"):
            returnVal += "        " + "scene = bge.logic.getCurrentScene()\n"
            returnVal += "        " + "self.gameObject = scene.objects[gameObject[\"" +nodeGuiData.getParam('String','Object') +"\"]]\n"
        returnVal += "        " + "self.x = " + str(nodeGuiData.getParam('float','x')) + "/10\n"
        returnVal += "        " + "self.y = " + str(nodeGuiData.getParam('float','y')) + "/10\n"
        returnVal += "        " + "self.z = " + str(nodeGuiData.getParam('float','z')) + "/10\n" 
        returnVal += "    def next(self):\n"
        returnVal += "        self.gameObject.applyRotation((self.x,self.y,self.z),True)\n"
        returnVal += "        return self.p0()\n"
        returnVal += "    def nextDelayed(self):\n"
        returnVal += "        return []\n"
        returnVal += "    def nextPortal(self):\n"
        returnVal += "        return []\n"


    elif(nodeGuiData.guidata['title'] == "If"):
        returnVal += "        " + "self.ifeval = '" + str(nodeGuiData.getParam('String','if')) + "'\n"
        returnVal += "    def next(self):\n"
        returnVal += "        if(eval(self.ifeval)):\n"
        returnVal += "            return self.p1()\n"
        returnVal += "        else:\n"
        returnVal += "            return self.p0()\n"
        returnVal += "    def nextDelayed(self):\n"
        returnVal += "        return []\n"
        returnVal += "    def nextPortal(self):\n"
        returnVal += "        return []\n"


    elif(nodeGuiData.guidata['title'] == "Set Property"):
        if(nodeGuiData.getParam('String','Object') != "gameObject"):
            returnVal += "        " + "scene = bge.logic.getCurrentScene()\n"
            returnVal += "        " + "self.gameObject = scene.objects[gameObject[\"" +nodeGuiData.getParam('String','Object') +"\"]]\n"
        returnVal += "        " + "self.propname = '" + str(nodeGuiData.getParam('String','name')) + "'\n"
        returnVal += "        " + "self.propvalue = '" + str(nodeGuiData.getParam('String','value')) + "'\n"
        returnVal += "    def next(self):\n"
        returnVal += "        self.gameObject[self.propname] = eval(self.propvalue)\n"
        returnVal += "        return self.p0()\n"
        returnVal += "    def nextDelayed(self):\n"
        returnVal += "        return []\n"
        returnVal += "    def nextPortal(self):\n"
        returnVal += "        return []\n"


    elif(nodeGuiData.guidata['title'] == "Add Object"):
        if(nodeGuiData.getParam('String','Object') != "gameObject"):
            returnVal += "        " + "scene = bge.logic.getCurrentScene()\n"
            returnVal += "        " + "self.gameObject = scene.objects[gameObject[\"" +nodeGuiData.getParam('String','Object') +"\"]]\n"
        returnVal += "        " + "self.objName = " + str(nodeGuiData.getParam('String','name')) + "\n"
        returnVal += "        " + "self.lifeTime = " + str(nodeGuiData.getParam('int','time')) + "\n"
        returnVal += "        " + "self.scene = bge.logic.getCurrentScene()\n"
        returnVal += "    def next(self):\n"
        returnVal += "        global Behaviours\n"
        returnVal += "        global BList\n"
        returnVal += "        scene = bge.logic.getCurrentScene()\n"
        returnVal += "        object = self.scene.addObject(self.objName, self.gameObject.name, self.lifeTime)\n"
        returnVal += "        return self.p0()\n"
        returnVal += "    def nextDelayed(self):\n"
        returnVal += "        return []\n"
        returnVal += "    def nextPortal(self):\n"
        returnVal += "        return []\n"


#        returnVal += "        if object in scene.objects:\n"
#        returnVal += "            print(object.name)\n"
#        returnVal += "            for behaviour in Behaviours:\n"
#        returnVal += "                print(object.getPropertyNames())\n"
#        returnVal += "                if(behaviour in object.getPropertyNames()):\n"
#        returnVal += "                    print(\"BList.append(\"+behaviour+\"(object))\")\n"
#        returnVal += "                    exec(\"BList.append(\"+behaviour+\"(object))\")\n"



    elif(nodeGuiData.guidata['title'] == "Action"):
        returnVal += "        " + "self.name = \"" + str(nodeGuiData.getParam('String','name')) + "\"\n"
        returnVal += "        " + "self.start = " + str(nodeGuiData.getParam('float','start')) + "\n"
        returnVal += "        " + "self.end = " + str(nodeGuiData.getParam('float','end')) + "\n" 
        returnVal += "        " + "self.layer = " + str(nodeGuiData.getParam('int','layer')) + "\n" 
        returnVal += "        " + "self.priority = " + str(nodeGuiData.getParam('int','priority')) + "\n" 
        returnVal += "        " + "self.blendin = " + str(nodeGuiData.getParam('int','blendin')) + "\n"

        playOption = nodeGuiData.getParam('combo','playmode')[1][nodeGuiData.getParam('combo','playmode')[0]]
        if(playOption == "Play"):
            playMode = "bge.logic.KX_ACTIONACT_PLAY"
        if(playOption == "Ping Pong"):
            playMode = "bge.logic.KX_ACTIONACT_PINGPONG"
        if(playOption == "Flipper"):
            playMode = "bge.logic.KX_ACTIONACT_FLIPPER"
        if(playOption == "Loop Stop"):
            playMode = "bge.logic.KX_ACTIONACT_LOOPSTOP"
        if(playOption == "Loop End"):
            playMode = "bge.logic.KX_ACTIONACT_LOOPEND"

        returnVal += "        " + "self.playmode = " + playMode + "\n"
        returnVal += "    def next(self):\n"
        returnVal += "        if(self.gameObject.invalid):\n"
        returnVal += "            return True\n"
        returnVal += "        self.gameObject.playAction(self.name, self.start, self.end, self.layer, self.priority, self.blendin, self.playmode)\n"
        returnVal += "        return self.p0()\n"
        returnVal += "    def nextDelayed(self):\n"
        returnVal += "            return []\n"
        returnVal += "    def nextPortal(self):\n"
        returnVal += "        return []\n"


    elif(nodeGuiData.guidata['title'] == "None"):
        returnVal += "    def next(self):\n"
        returnVal += "        return self.p0()\n"
        returnVal += "    def nextDelayed(self):\n"
        returnVal += "            return []\n"
        returnVal += "    def nextPortal(self):\n"
        returnVal += "        return []\n"

    elif(nodeGuiData.guidata['title'] == "Delay"):
        if(not is_int(nodeGuiData.getParam('String','Delay Time'))):
            returnVal += "        " + "self.delay = gameObject[\"" +nodeGuiData.getParam('String','Delay Time') +"\"]\n"
        else:
            returnVal += "        " + "self.delay = " +nodeGuiData.getParam('String','Delay Time') +"\n"
        returnVal += "    def next(self):\n"
        returnVal += "        return []\n"
        returnVal += "    def nextDelayed(self):\n"
        returnVal += "            returnVal = []\n"
        returnVal += "            for next in self.p0():\n"
        returnVal += "                returnVal += [[next, self.delay]]\n"
        returnVal += "            return returnVal\n"
        returnVal += "    def nextPortal(self):\n"
        returnVal += "        return []\n"

    elif(nodeGuiData.guidata['title'] == "Portal"):
        returnVal += "        " + "self.portal = " +nodeGuiData.getParam('String','Portal') +"\n"
        returnVal += "        " + "self.object = " +nodeGuiData.getParam('String','Object') +"\n"
        returnVal += "    def next(self):\n"
        returnVal += "        return []\n"
        returnVal += "    def nextDelayed(self):\n"
        returnVal += "        return []\n"
        returnVal += "    def nextPortal(self):\n"
        returnVal += "        return [[self.portal,self.object]] \n"

    elif(nodeGuiData.guidata['title'] == "Portal In"):
        returnVal += "    def start(self, object ,main):\n"
        returnVal += "        if(object == \"All\" or object == self.gameObject.name):\n"
        returnVal += "            main.mainLoop(self.p0())\n"
        returnVal += "    def next(self):\n"
        returnVal += "        return []\n"
        returnVal += "    def nextDelayed(self):\n"
        returnVal += "        return []\n"
        returnVal += "    def nextPortal(self):\n"
        returnVal += "        return []\n"
    if(nodeGuiData.guidata['title'] == "Set Velocity"):
        if(nodeGuiData.getParam('String','Object') != "gameObject"):
            returnVal += "        " + "scene = bge.logic.getCurrentScene()\n"
            returnVal += "        " + "self.gameObject = scene.objects[gameObject[\"" +nodeGuiData.getParam('String','Object') +"\"]]\n"
        returnVal += "        " + "self.x = " + str(nodeGuiData.getParam('float','x')) + "/10\n"
        returnVal += "        " + "self.y = " + str(nodeGuiData.getParam('float','y')) + "/10\n"
        returnVal += "        " + "self.z = " + str(nodeGuiData.getParam('float','z')) + "/10\n"
        returnVal += "    def next(self):\n"
        returnVal += "        self.gameObject.setLinearVelocity((self.x,self.y,self.z),True)\n"
        returnVal += "        return self.p0()\n"
        returnVal += "    def nextDelayed(self):\n"
        returnVal += "            return []\n"
        returnVal += "    def nextPortal(self):\n"
        returnVal += "        return []\n"


    if(nodeGuiData.guidata['title'] == "Collides"):
        if(nodeGuiData.getParam('String','Object') != "gameObject"):
            returnVal += "        " + "scene = bge.logic.getCurrentScene()\n"
            returnVal += "        " + "self.gameObject = scene.objects[gameObject[\"" +nodeGuiData.getParam('String','Object') +"\"]]\n"
        returnVal += "    def next(self):\n"
        returnVal += "        " + "hitVector = (self.gameObject.localPosition[0], self.gameObject.localPosition[1], self.gameObject.localPosition[2]-1) \n"
        returnVal += "        " + "hit = hit = self.gameObject.rayCast(hitVector, self.gameObject,1,\"Floor\")\n"
        returnVal += "        if(hit[0] is not None):\n"
        returnVal += "            return self.p1()\n"
        returnVal += "        else:\n"
        returnVal += "            return self.p0()\n"
        returnVal += "    def nextDelayed(self):\n"
        returnVal += "            return []\n"
        returnVal += "    def nextPortal(self):\n"
        returnVal += "        return []\n"


    for pin in node.outPins:
        returnVal += "    def p" + pin.name + "(self):\n"
        returnVal += "        return ["
        first = True
        for line in pin.lines:
            if not first:
                returnVal += ","
            else:
                first= False
            returnVal += "\"" + line.fNode.node.name + "\""
        returnVal += "]\n"
    print(returnVal)
    return str(returnVal)

def BaseNodeData(data):
    if(data == "None"):
        nodeGuiData = baseNode()
        dic = {"title": "None", 'paramtypes': []}
        return nodeGuiData
    if(data == "Move"):
        nodeGuiData = baseNode()
        dic = {"title": "Move", 'paramtypes': []}
        nodeGuiData.setGuiData(dic)
        nodeGuiData.setValue('String','Object',"gameObject")
        nodeGuiData.setValue('float','x',0)
        nodeGuiData.setValue('float','y',0)
        nodeGuiData.setValue('float','z',0)
        return nodeGuiData
    elif(data == "Keyboard"):
        nodeGuiData = baseNode()
        dic = {"title": "Keyboard", 'paramtypes': []}
        nodeGuiData.setGuiData(dic)
        nodeGuiData.setValue('char','key','e')
        nodeGuiData.setValue('combo', 'Type', [0, ["Just Activated", "Active", "Just Released"]])
        return nodeGuiData

    elif(data == "Rotate"):
        nodeGuiData = baseNode()
        dic = {"title": "Rotate", 'paramtypes': []}
        nodeGuiData.setGuiData(dic)
        nodeGuiData.setValue('String','Object',"gameObject")
        nodeGuiData.setValue('float','x',0)
        nodeGuiData.setValue('float','y',0)
        nodeGuiData.setValue('float','z',0)
        return nodeGuiData

    elif(data == "Action"):
        nodeGuiData = baseNode()
        dic = {"title": "Action", 'paramtypes': []}
        nodeGuiData.setGuiData(dic)
        nodeGuiData.setValue('String','Object',"gameObject")
        nodeGuiData.setValue('String','name',"")
        nodeGuiData.setValue('float','start',0)
        nodeGuiData.setValue('float','end',1)
        nodeGuiData.setValue('int','layer',0)
        nodeGuiData.setValue('int','priority',0)
        nodeGuiData.setValue('int','blendin',0)
        nodeGuiData.setValue('combo', 'playmode', [0, ["Play", "Flipper", "Ping Pong","Loop End", "Loop Stop", "Property"]])
        return nodeGuiData
    elif(data == "If"):
        nodeGuiData = baseNode()
        dic = {"title": "If", 'paramtypes': []}
        nodeGuiData.setGuiData(dic)
        nodeGuiData.setValue('String','if',"True")
        return nodeGuiData

    elif(data == "Add Object"):
        nodeGuiData = baseNode()
        dic = {"title": "Add Object", 'paramtypes': []}
        nodeGuiData.setGuiData(dic)
        nodeGuiData.setValue('String','Object',"gameObject")
        nodeGuiData.setValue('String','name',"")
        nodeGuiData.setValue('int','time', 0)
        return nodeGuiData

    elif(data == "Set Property"):
        nodeGuiData = baseNode()
        dic = {"title": "Set Property", 'paramtypes': []}
        nodeGuiData.setGuiData(dic)
        nodeGuiData.setValue('String','Object',"gameObject")
        nodeGuiData.setValue('String','name',"")
        nodeGuiData.setValue('String','value',"")
        return nodeGuiData
    elif(data == "Delay"):
        nodeGuiData = baseNode()
        dic = {"title": "Delay", 'paramtypes': []}
        nodeGuiData.setGuiData(dic)
        nodeGuiData.setValue('String','Delay Time',"1")
        return nodeGuiData

    elif(data == "Portal"):
        nodeGuiData = baseNode()
        dic = {"title": "Portal", 'paramtypes': []}
        nodeGuiData.setGuiData(dic)
        nodeGuiData.setValue('String','Portal','\"Name\"')
        nodeGuiData.setValue('String','Object','\"All\"')
        return nodeGuiData

    elif(data == "Portal In"):
        nodeGuiData = baseNode()
        dic = {"title": "Portal In", 'paramtypes': []}
        nodeGuiData.setGuiData(dic)
        return nodeGuiData

    if(data == "Set Velocity"):
        nodeGuiData = baseNode()
        dic = {"title": "Set Velocity", 'paramtypes': []}
        nodeGuiData.setGuiData(dic)
        nodeGuiData.setValue('String','Object',"gameObject")
        nodeGuiData.setValue('float','x',0)
        nodeGuiData.setValue('float','y',0)
        nodeGuiData.setValue('float','z',0)
        return nodeGuiData

    if(data == "Collides"):
        nodeGuiData = baseNode()
        dic = {"title": "Collides", 'paramtypes': []}
        nodeGuiData.setGuiData(dic)
        nodeGuiData.setValue('String','Object',"gameObject")
        return nodeGuiData


class SecondDialog(sc.SizedDialog):  
    def __init__(self, parent, id, nodeGuiData, NodeData):  
        sc.SizedDialog.__init__(self, None, -1, NodeData.name, style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)            
        pane = self.GetContentsPane()  
        pane.SetSizerType("form")
        self.Vars = {}
        for par in nodeGuiData.getParamTypes():
            for var in nodeGuiData.getParamNames(par):
                if(par == "char" or par == "String"):
                    wx.StaticText(pane, -1, var)
                    self.Vars[var] =  wx.TextCtrl(pane, -1, nodeGuiData.getParam(par,var), (40,40), (160,-1))
                elif(par == "int"):
                    wx.StaticText(pane, -1, var)
                    self.Vars[var] = wx.SpinCtrl(pane, -1, "", (40,40), (60,-1))
                    self.Vars[var].SetRange(-1000,1000)
                    self.Vars[var].SetValue(nodeGuiData.getParam(par,var))
                elif(par == "float"):
                    wx.StaticText(pane, -1, var)
                    self.Vars[var] = wx.SpinCtrl(pane, -1, "", (40,40), (60,-1))
                    self.Vars[var].SetRange(-1000,1000)
                    self.Vars[var].SetValue(nodeGuiData.getParam(par,var))
                elif(par == "combo"):
                    wx.StaticText(pane, -1, var)
                    indexvalue = nodeGuiData.getParam(par,var)[0]
                    optionlist = nodeGuiData.getParam(par,var)[1]
                    self.Vars[var] = wx.Choice(pane, indexvalue, (40,40), (120,-1),optionlist)

                    


        RUN_BUTTON = self.SetButtonSizer(self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL))

        self.Fit()
        self.SetMinSize(self.GetSize())


class Dialog(sc.SizedDialog):  
    def __init__(self, parent, id, Nodes, NodeData):  
        sc.SizedDialog.__init__(self, None, -1, NodeData.name, style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)            
        pane = self.GetContentsPane()  
        pane.SetSizerType("form")  

        wx.StaticText(pane, -1, "Name:")
        self.N1_BOX = wx.TextCtrl(pane, -1, NodeData.name, (40,40), (120,-1))

        wx.StaticText(pane, -1, "Type:")
        self.C1_BOX = wx.Choice(pane, -1, (40,40), (120,-1),Nodes)
        #self.C1_BOX.SetRange(1,1000)
        #self.C1_BOX.SetValue(2)

        RUN_BUTTON = self.SetButtonSizer(self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL))

        self.Fit()
        self.SetMinSize(self.GetSize())

class Node(object):
    def __init__(self, x, y, size, color="Green", name="Nombre", NodeData = None):
        self.x = x
        self.y = y
        self.width = size	
        self.heigth = size
        self.size = size
        self.color = color
        self.name = name
        self.pinSize = self.width/20
        self.outPins = []
        self.inPins=[]
        self.pinOffset = size*0.1
        self.pinspacer = 5
        self.NodeData = baseNode()
        self.type = "None"
        self.hidden = False
        
    def setNodeData(self, NodeData):
        self.NodeData = NodeData
        if(self.width > self.size):
            self.width = self.size
            self.update(self.x, self.y)  
    def draw(self, dc):
        dc.SetPen(wx.Pen(self.color, 2))
        dc.DrawText(self.name, self.x, self.y-20)
        dc.SetBrush(wx.GREEN_BRUSH)
        dc.DrawRectangle(self.x, self.y, self.width, self.heigth)
        dc.SetPen(wx.Pen("Blue", 2))
        dc.SetBrush(wx.BLUE_BRUSH)
        for pin in self.outPins:
            dc.DrawText(pin.name, pin.x-self.pinSize, pin.y-25)
            dc.DrawCircle(pin.x,pin.y, self.pinSize)
        dc.SetPen(wx.Pen("Black", 2))
        dc.SetBrush(wx.Brush("yellow"))
        for pin in self.inPins:
            dc.DrawText(pin.name, pin.x-self.pinSize, pin.y-25)
            dc.DrawCircle(pin.x,pin.y, self.pinSize)
        dc.DrawText("Type: " + self.type, self.x+self.pinSize*3, self.y)
        varHeight = 1
        if(self.NodeData is not None):
            if(self.width > self.size):
                self.width = self.size
            varHeigth = 1
            if self.hidden:
                self.heigth = self.size
                self.update(self.x, self.y)
            else:
                for par in self.NodeData.getParamTypes():
                    for var in self.NodeData.getParamNames(par):                               
                        dc.DrawText(var + ": ", self.x+self.pinSize*4, self.y + varHeigth*25)   
                        (TextWidth, TextHeight) = dc.GetTextExtent(var+ ": ")
                        if(par == "combo"):
                            comboOptions = self.NodeData.getParam(par, var)[1]
                            comboIndex = self.NodeData.getParam(par, var)[0]
                            dc.DrawText(str(comboOptions[comboIndex]), self.x+self.pinSize*4 + TextWidth, self.y + varHeigth*25)
                            (TextWidth, TextHeight) = dc.GetTextExtent(var+ ": "+ str(comboOptions[comboIndex]))
          
                            while TextWidth > self.width*.8:
                                self.width = self.width*1.1
                                self.update(self.x, self.y)
                        else:
                            dc.DrawText(str(self.NodeData.getParam(par,var)), self.x+self.pinOffset+self.pinSize*3 + TextWidth, self.y + varHeigth*25)
                            (TextWidth, TextHeigth) = dc.GetTextExtent(var+ ": "+ str(self.NodeData.getParam(par,var)))
                       
                            while (TextWidth > self.width*.8):
                                self.width = self.width*1.1
                                self.update(self.x, self.y)
                        varHeigth += 1

                if(varHeigth > 4 and  self.heigth < ((varHeigth+1)*self.size)/5 ):
                    self.heigth = ((varHeigth+1)*self.size)/5
                    self.update(self.x, self.y)
                
                elif(varHeigth < 4):
                    self.heigth = self.size
                    self.update(self.x, self.y)

    def appendOutPin(self, Pin):
        Pin.x = self.x + self.width-self.pinOffset
        Pin.place = len(self.outPins)+1
        self.outPins.append(Pin)
        if self.heigth/len(self.outPins)< self.pinSize*self.pinspacer:
            self.heigth = self.heigth + self.pinSize*self.pinspacer
        for p in self.outPins:
            p.y = self.y + self.heigth*p.place/(len(self.outPins))-self.pinSize

    def appendInPin(self, Pin):
        Pin.x = self.x + self.pinOffset
        Pin.place = len(self.inPins)+1
        self.inPins.append(Pin)
        if self.heigth/len(self.inPins)< self.pinSize*self.pinspacer:
            self.heigth = self.heigth + self.pinSize*self.pinspacer
        for p in self.inPins:
            p.y = self.y + self.heigth*p.place/(len(self.inPins))-self.pinSize

    def getOutPin(self, x, y):
        for p in self.outPins:
            if x > p.x-self.pinSize and x< p.x + self.pinSize and y > p.y-self.pinSize and y < p.y+self.pinSize:
                return p
    def getInPin(self, x, y):
        for p in self.inPins:
            if x > p.x-self.pinSize and x< p.x + self.pinSize and y > p.y-self.pinSize and y < p.y+self.pinSize:
                return p

    def update(self, x, y):
        self.x = x
        self.y = y
        for p in self.outPins:
            p.x = self.x + self.width - self.pinOffset
            p.y = self.y + self.heigth*(p.place)/(len(self.outPins))-self.pinSize
        for p in self.inPins:
            p.x = self.x + self.pinOffset
            p.y = self.y + self.heigth*(p.place)/(len(self.inPins))-self.pinSize

class Pin(object):
    def __init__(self,x, y,node,name="pin"):
        self.x = x
        self.y = y
        self.name = name
        self.place = 1
        self.node = node
        self.lines = []
    def appendLine(self, line):
        self.lines.append(line)
    def remLine(self, line):
        self.lines.remove(line)

class Connection(object):
    def __init__(self, x, y, sNode, color="BLACK"):
        self.x = x
        self.y = y
        self.sNode = sNode
        self.color = color
        self.fNode = None
    def draw(self, dc):
        dc.SetPen(wx.Pen(self.color, 3))
        if self.fNode is None:
            dc.DrawLine(self.sNode.x, self.sNode.y,self.x,self.y)
        else:
            dc.DrawLine(self.sNode.x, self.sNode.y, self.fNode.x, self.fNode.y)
    def update(self, x, y):
        self.x = x
        self.y = y

class NodePanel(wx.Window):
    def __init__(self, parent):

        self.moveX=0
        self.moveY=0
        self.panning=False
        self.checkingLine = False

        wx.Window.__init__(self, parent)
        self.bubbles = []
	self.nodes = []
        self.marks = []
        self.lines = []
	self.movingRect = False
        self.rect = None
        self.connecting = False
        self.connector = None
        self.last_pos = self.ScreenToClient(wx.GetMousePosition())
        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
        self.SetBackgroundColour("WHITE")

        self.Bind(wx.EVT_PAINT, self.on_paint)
        self.Bind(wx.EVT_SIZE, self.on_size)

        self.Bind(wx.EVT_MOTION, self.on_motion)
        self.Bind(wx.EVT_LEFT_UP, self.on_left_up)
        self.Bind(wx.EVT_RIGHT_UP, self.on_right_up)
        self.Bind(wx.EVT_CHAR, self.on_character)
        #self.Bind(wx.EVT_KEY_DOWN, self.on_key_down)
        self.Bind(wx.EVT_LEFT_DOWN, self.on_left_down)
        self.Bind(wx.EVT_RIGHT_DOWN, self.on_right_down)
        self.Bind(wx.EVT_MIDDLE_DOWN, self.on_middle_down)
        self.Bind(wx.EVT_MIDDLE_UP, self.on_middle_up)
        self.Bind(wx.EVT_LEFT_DCLICK, self.on_left_double_click)
        wx.FutureCall(200, self.SetFocus)

    def setNodes(self, nodes):
        self.nodes = nodes
    def setLines(self, lines):
        self.lines = lines
    def on_size(self, event):
        width, height = self.GetClientSize()
        self._buffer = wx.EmptyBitmap(width, height)
        self.update_drawing()
    def updateSizeBind(self):
        self.Bind(wx.EVT_SIZE, self.on_size)

    def update_drawing(self):
        self.Refresh(False)

    def on_paint(self, event):
        dc = wx.AutoBufferedPaintDC(self)
        dc.Clear()
        x, y = self.ScreenToClient(wx.GetMousePosition())
        if(self.checkingLine):
            self.draw_I(dc, x, y, 4)
        else:
            self.draw_x(dc, x, y, 4)
        for bubble in self.bubbles:
            bubble.draw(dc, self.bubbles)
        self.draw_marks(dc)
        for node in self.nodes:
            node.draw(dc)
        for line in self.lines:
            line.draw(dc)
        if self.movingRect:
            self.rect.update(self.last_pos.x,self.last_pos.y)
        if self.connecting:
            self.connector.update(self.last_pos.x,self.last_pos.y)
        
        if(self.panning):
            (self.moveX, self.moveY)=(x-self.last_pos.x, y-self.last_pos.y)
            print(self.moveX)
            if self.moveX!=0 or self.moveY!=0:
                for node in self.nodes:
                    node.update(node.x+self.moveX,node.y+self.moveY)
        if self.checkingLine:
            for line in self.lines:
                if self.checkiInLine(line,x,y) :
                    line.sNode.remLine(line)
                    line.fNode.remLine(line)
                    self.lines.remove(line)
                    del(line)
        self.last_pos = wx.Point(x, y)


    def draw_x(self, dc, x, y, line_width):
        dc.SetPen(wx.Pen("BLACK", line_width))
        dc.DrawLine(x-5, y-5, x+5, y+5)  # \
        dc.DrawLine(x-5, y+5, x+5, y-5)  # /
    def draw_I(self, dc, x, y, line_width):
        dc.SetPen(wx.Pen("BLACK", line_width))
        dc.DrawLine(x-10, y+10, x, y)  # /

    def draw_marks(self, dc):
        chains = {}
        for (letter, x, y) in self.marks:
            self.draw_x(dc, x, y, 2)
            dc.DrawText(letter, x-3, y-28)
            chains.setdefault(letter, []).append(wx.Point(x,y))
        for (key, points) in chains.items():
            if len(points) > 1:
                if key == key.upper() or len(points) == 2:
                    dc.DrawLines(points)
                else:
                    dc.DrawSpline(points)

    def between(self, (x,y), begin, end):
        if(begin.x<= x <= end.x or begin.x>= x >= end.x):
            if begin.y<= y <= end.y or begin.y >= y >= end.y:
                return True
        return False
        
    def checkiInLine(self, line,x,y):
        #check a rectangle area near the line
        if self.between((x,y),line.sNode,line.fNode):
            (vectXLine, vectYLine) = (line.fNode.x-line.sNode.x,line.fNode.y-line.sNode.y)
            (vectXMouse, vectYMouse) = (x-line.sNode.x,y-line.sNode.y) 
            if vectXLine == 0:
                return True
            if vectYLine == 0:
                return True
            #check close to the line
            if float(float(vectXMouse)/float(vectXLine))-0.1<float(float(vectYMouse)/float(vectYLine)):
                if float(float(vectXMouse)/float(vectXLine))+0.1>float(float(vectYMouse)/float(vectYLine)):
                    return True
            else:
                return False
            
    def checkNode(self, x, y):
        for node in self.nodes:
            if x > node.x and x< node.x + node.width and y > node.y and y < node.y+node.heigth:
                return node
    def checkOutPin(self,x,y):
        node = self.checkNode(x,y)
        if node is not None:
            return node.getOutPin(x,y)

    def checkInPin(self,x,y):
        node = self.checkNode(x,y)
        if node is not None:
            return node.getInPin(x,y)



    def on_motion(self, event):
        x, y = event.GetPosition()
     #   motion_score = (abs(x - self.last_pos.x) + abs(y - self.last_pos.y))
     #   self.last_pos = wx.Point(x, y)

    def on_left_double_click(self,event):
        node = self.checkNode(event.GetX(), event.GetY())
        if node is not None:
        #    dialog = wx.TextEntryDialog ( None, 'Node Name:', 'Editing Node', node.name )
        #    # If the user presses, "OK", print the value. Otherwise, print another message.
        #    if dialog.ShowModal() == wx.ID_OK:
        #        node.name = dialog.GetValue()
        #    else:
        #        print 'You did not push the "OK" button.'
        #    # Destroy the dialog
            nodeOptions = DEFINEDNODES
            dlg = Dialog(None, -1, nodeOptions, node)
            dlgrslt = dlg.ShowModal()

            if dlgrslt != wx.ID_OK:
                print ('Exiting..')
                exit
                dlg.Destroy()
            else:
                pass
                print (dlg.N1_BOX.GetValue())
                node.name = dlg.N1_BOX.GetValue()
                if(node.type == nodeOptions[dlg.C1_BOX.GetCurrentSelection()]):
                    nodeGuiData = node.NodeData
                #print (N1+N2/T1-T2)
                else:
                    nodeGuiData = BaseNodeData(nodeOptions[dlg.C1_BOX.GetCurrentSelection()])
                    node.setNodeData(nodeGuiData)
                    node.type = nodeOptions[dlg.C1_BOX.GetCurrentSelection()]
                dlg.Destroy()
                dlg = SecondDialog(None, -1, nodeGuiData, node)
                dlgrslt = dlg.ShowModal()

                if dlgrslt != wx.ID_OK:
                    print ('Exiting..')
                    exit
                    dlg.Destroy()
                else:
                    print(nodeGuiData.getParamTypes())
                    for par in nodeGuiData.getParamTypes():
                        for var in nodeGuiData.getParamNames(par):
                            if(par == "combo"):
                                comboOptions = nodeGuiData.getParam(par, var)[1]
                                comboIndex = dlg.Vars[var].GetSelection()
                                nodeGuiData.setValue(par,var, [comboIndex, comboOptions])
                                comboIndex = nodeGuiData.getParam(par, var)[0]
                                comboOptions = nodeGuiData.getParam(par, var)[1]
                                print(comboOptions[comboIndex])
                                
                            else:
                                nodeGuiData.setValue(par,var, dlg.Vars[var].GetValue())
                                print(nodeGuiData.getParam(par, var))
                    node.setNodeData(nodeGuiData)
                    dlg.Destroy()



    def on_right_up(self, event):
        if self.checkingLine:
            self.checkingLine = False
        if self.movingRect:
            self.movingRect = False
            node = None


    def on_right_down(self, event):
        if event.ControlDown():
            self.checkingLine=True
        else:
            if not self.movingRect:
                node = self.checkNode(event.GetX(), event.GetY())
                if node is not None:
                    self.movingRect = True
                    self.rect = node
            
    def on_left_up(self, event):
        if self.connecting:
            self.connecting = False
            pin = self.checkInPin(event.GetX(), event.GetY())
            if pin is not None:
                self.connector.fNode = pin
                self.connector.sNode.appendLine(self.connector)
                self.connector.fNode.appendLine(self.connector)
            else:
                self.lines.remove(self.connector)
                del self.connector

    def on_left_down(self, event):
        pin = self.checkOutPin(event.GetX(), event.GetY())
        if pin is not None:
            self.connector = Connection(event.GetX(), event.GetY(), pin, color="BLACK")
            self.lines.append(self.connector)
            self.connecting = True

    def on_middle_down(self, event):
        self.panning=True

    def on_middle_up(self, event):
        self.panning=False


    def on_character(self, event):
        key = event.GetKeyCode()
        print(key)
        x, y = self.ScreenToClient(wx.GetMousePosition())
        print(key)
        if key ==104: #h
            node = self.checkNode(x, y)
            if node is not None:
                node.hidden = not node.hidden
        if key ==13: #Enter
            node = Node(x, y, size=130, color = "BLACK", name="Node" + str(len(self.nodes)) )
            nodeGuiData = BaseNodeData("None")
            node.setNodeData(nodeGuiData)
            node.type = "None"
            self.nodes.append(node)
            print(event.GetX())
        if key== 127: #Supr
            node = self.checkNode(x, y)
            if node is not None:
                self.nodes.remove(node)
        if key==111: #o
            node = self.checkNode(x, y)
            print(x,y)
            if node is not None:
                node.appendOutPin(Pin(0,0, node, str(len(node.outPins)) ))
        if key == 105: #i
            node = self.checkNode(x, y)
            print(x,y)
            if node is not None:
                node.appendInPin(Pin(0,0, node, str(len(node.inPins))))
        if key==27:   # Esc key
            self.marks = []
        else:
            x, y = self.ScreenToClient(wx.GetMousePosition())
           # self.marks.append( (chr(event.GetKeyCode()), x, y) )



class NodeFrame(wx.Frame):
    def __init__(self, *args, **kw):
        wx.Frame.__init__(self, *args, **kw)
        self.Bind(wx.EVT_CLOSE, self.on_close)
        self.Bind(wx.EVT_TIMER, self.on_timer)

        self.panel = NodePanel(self)
        self.timer = wx.Timer(self)
        self.timer.Start(20)
        
        filemenu= wx.Menu()
        menuOpen = filemenu.Append(wx.ID_OPEN, "&Open"," Open a file to edit")
        menuSave= filemenu.Append(wx.ID_SAVE, "&Save"," Save to a file")
        menuCompile= filemenu.Append(wx.ID_ANY, "&Compile", " Make executable code from graph")
        menuExit = filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")

        # Creating the menubar.
        menuBar = wx.MenuBar()
        menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar
        self.SetMenuBar(menuBar)  # Adding the MenuBar to the Frame content.

        # Events.
        self.Bind(wx.EVT_MENU, self.on_open, menuOpen)
        self.Bind(wx.EVT_MENU, self.on_close, menuExit)
        self.Bind(wx.EVT_MENU, self.on_save, menuSave)
        self.Bind(wx.EVT_MENU, self.on_compile, menuCompile)

    def on_open(self,e):
        dlg = wx.FileDialog(
            self, message="Choose a file",
            defaultDir= os.getcwd(), 
            defaultFile="",
            #wildcard=wildcard,
            style=wx.OPEN| wx.CHANGE_DIR
            )
        if dlg.ShowModal() == wx.ID_OK:
            paths = dlg.GetPaths()
            print "You chose the following file(s):"
            for path in paths:
                print path
                f = open(path, "r")
                (Nodos, Lineas) = pickle.load(f)
                self.panel.setNodes(Nodos)
                #self.panel.setLines(Lines)
                self.panel.setLines(Lineas)
                f.close()
                self.panel.updateSizeBind()
        dlg.Destroy()
	self.panel.updateSizeBind()
    def on_save(self,e):
        dlg = wx.FileDialog(
            self, message="Save file",
            defaultDir=os.getcwd(),
            defaultFile="Nodos",
            #wildcard=wildcard,
            style=wx.SAVE | wx.CHANGE_DIR
            )
        if dlg.ShowModal() == wx.ID_OK:
            paths = dlg.GetPaths()
            print "You chose the following file(s):"
            for path in paths:
                print path
                #self.panel.save(path)
                f = open(path, 'wb')
                pickle.dump((self.panel.nodes, self.panel.lines),f)
                f.close()
        dlg.Destroy()

    def on_compile(self,e):
        dlg = wx.FileDialog(
            self, message="Compile file",
            defaultDir=os.getcwd(),
            defaultFile="Behaviour",
            #wildcard=wildcard,
            style=wx.SAVE | wx.CHANGE_DIR
            )
        if dlg.ShowModal() == wx.ID_OK:
            paths = dlg.GetPaths()
            print "You chose the following file(s):"
            for path in paths:
                print path
                f = open(path, 'w')
                for node in self.panel.nodes:
                    print(node)
                  #  f.write("class " + node.name + "(object):\n")
                    f.write("import bge\n")
                    print(NodeToCode(node, node.NodeData))
                    f.write(NodeToCode(node, node.NodeData))
                    #f.write("    def __init__(self, gameObject):\n")
                    #f.write("        self.gameObject=gameObject\n")
                    #f.write("    def next(self):\n")
                    #f.write("        print(\"" + node.name + "\")\n")
                    #f.write("        returnVal = []\n")
                    #for pin in node.outPins:
                    #    f.write("        returnVal += self.p" + pin.name + "()\n")
                    #f.write("        return returnVal\n")
                    #for pin in node.outPins:
                    #    f.write("    def p" + pin.name + "(self):\n")
                    #    f.write("        return [")
                    #    first = True
                    #    for line in pin.lines:
                    #        if not first:
                    #            f.write(",")
                    #        else:
                    #            first= False
                    #        f.write("\"" + line.fNode.node.name + "\"")
                    #    f.write("]\n")
                f.write("class main(object):\n")
                f.write("    def __init__(self, gameObject):\n")
                f.write("        self.Nodes = {}\n")
                f.write("        self.gameObject = gameObject\n")
                f.write("        self.delayList = []\n")
                for node in self.panel.nodes:
                    f.write("        self.Nodes['" + node.name + "'] = " + node.name +"(self.gameObject)\n")
                f.write("    def mainLoop(self, List = ['Node0']):\n")
                f.write("        returnList = []\n")
                f.write("        if(List[0] != 'Node0'):\n")
                f.write("            List=List\n")
                f.write("        else:\n")
                f.write("            List=['Node0']\n")
                f.write("        Sum = None\n")
                f.write("        for delayedNode in self.delayList:\n")
                f.write("            if(delayedNode[1]<1):\n")
                f.write("                List += [delayedNode[0]]\n")
                f.write("                self.delayList.remove(delayedNode)\n")
                f.write("            else:\n")
                f.write("                delayedNode[1] -= 1\n")
                f.write("        for nodeName in List:\n")
                f.write("            if nodeName is not None:\n")
#               f.write("            List.remove(nodeName)\n")
                f.write("                if(nodeName in self.Nodes):\n")
                f.write("                    Sum = self.Nodes[nodeName].next()\n")
                f.write("                    if(Sum is not None):\n")
                f.write("                        List += Sum\n")
                f.write("                    if len(self.Nodes[nodeName].nextDelayed())>0:\n")
                f.write("                        self.delayList += self.Nodes[nodeName].nextDelayed()\n")
                f.write("                    if len(self.Nodes[nodeName].nextPortal())>0:\n")
                f.write("                        returnList += self.Nodes[nodeName].nextPortal()\n")
                f.write("        return returnList\n")
                f.close()        
        dlg.Destroy()

    def on_close(self, event):
        self.timer.Stop()
        self.Destroy()

    def on_timer(self, event):
        self.panel.update_drawing()


app = wx.App(False)
frame = NodeFrame(None, -1, "Sven's Node Editor")
frame.Show(True)
app.MainLoop()
